﻿using System;

namespace FlightToolkit.SimProp
{
    internal class PropertyDescriptor : System.ComponentModel.PropertyDescriptor
    {
        private PropertySet _owner;
        private Property _property;

        public PropertyDescriptor(PropertySet owner, Property property)
            : base(property.Name, null)
        {
            this._property = property;
            this._owner = owner;
        }

        public override bool Equals(object obj)
        {
            var other = obj as PropertyDescriptor;
            return other != null && other._property.Name.Equals(this._property.Name);
        }

        public override int GetHashCode() { return this._property.Name.GetHashCode(); }

        public override bool IsReadOnly { get { return false; } }

        public override void ResetValue(object component) { }

        public override bool CanResetValue(object component) { return false; }

        public override bool ShouldSerializeValue(object component)
        {
            return true;
        }

        public override System.Type ComponentType
        {
            get { return _owner.GetType(); }
        }

        public override System.Type PropertyType
        {
            get
            {
                return this._property.def.SystemType;
            }
        }

        public override object GetValue(object component)
        {
            switch (this._property.Type)
            {
                case SimProp.Type.Bool:
                    return this._property.Int[0] != 0;
                case SimProp.Type.Byte4:
                    return this._property.Byte;
                case SimProp.Type.Double:
                    return this._property.Double[0];
                case SimProp.Type.LLA:
                    return this._property.Double;
                case SimProp.Type.Filetime:
                    return this._property.Filetime;
                case SimProp.Type.Float:
                    return this._property.Float[0];
                case SimProp.Type.Float2:
                case SimProp.Type.Float3:
                case SimProp.Type.Float4:
                case SimProp.Type.Matrix:
                case SimProp.Type.PBH:
                    return this._property.Float;
                case SimProp.Type.Guid:
                    return this._property.Guid;
                case SimProp.Type.Enum:
                    return Enum.ToObject(this._property.def.SystemType, this._property.Int[0]);
                case SimProp.Type.Long:
                case SimProp.Type.ULong:
                    return this._property.Int[0];
                case SimProp.Type.Long2:
                case SimProp.Type.Long3:
                case SimProp.Type.Long4:
                    return this._property.Int;
                case SimProp.Type.String:
                    return this._property.String;
                default:
                    throw new Exception("Invalid property type");
            }
        }

        public override void SetValue(object component, object value)
        {
            OnValueChanged(component, EventArgs.Empty);
            switch (this._property.Type)
            {
                case SimProp.Type.Bool:
                    this._property.Int[0] = ((bool)value) ? 1 : 0;
                    break;
                case SimProp.Type.Byte4:
                    ((byte[])value).CopyTo(this._property.Byte, this._property.Byte.Length);
                    break;
                case SimProp.Type.Double:
                    this._property.Double[0] = ((double)value);
                    break;
                case SimProp.Type.LLA:
                    ((double[])value).CopyTo(this._property.Double, this._property.Double.Length);
                    break;
                case SimProp.Type.Filetime:
                    this._property.Filetime = ((DateTime)value);
                    break;
                case SimProp.Type.Float:
                    this._property.Float[0] = ((float)value);
                    break;
                case SimProp.Type.Float2:
                case SimProp.Type.Float3:
                case SimProp.Type.Float4:
                case SimProp.Type.Matrix:
                case SimProp.Type.PBH:
                    ((float[])value).CopyTo(this._property.Float, this._property.Float.Length);
                    break;
                case SimProp.Type.Guid:
                    this._property.Guid = ((Guid)value);
                    break;
                case SimProp.Type.Enum:
                case SimProp.Type.Long:
                case SimProp.Type.ULong:
                    this._property.Int[0] = ((int)value);
                    break;
                case SimProp.Type.Long2:
                case SimProp.Type.Long3:
                case SimProp.Type.Long4:
                    ((int[])value).CopyTo(this._property.Int, this._property.Int.Length);
                    break;
                case SimProp.Type.String:
                    this._property.String = ((string)value);
                    break;
                default:
                    throw new Exception("Invalid property type");
            }
        }
    }
}
